from django.http import JsonResponse
from django.shortcuts import render
from django.views import View
import json
import pickle,base64
from django_redis import get_redis_connection

from apps.goods.models import SKU


# Create your views here.


class CartsView(View):
    # 保存购物车数据
    def post(self,request):
        # 1获取前端数据，json类型
        data_json = request.body.decode()
        # 2将json数据转化为字典
        data_dict = json.loads(data_json)
        # 3提取字段，商品数量，id，选中状态
        sku_id = data_dict.get('sku_id')
        count = data_dict.get('count')
        # 前端未传递selected，可赋值True，字典get方法获取数据不存在，给一个默认值
        selected = data_dict.get('selected',True)
        # 4验证数据
        # 验证数据完整性
        if not all([sku_id,count,selected]):
            return JsonResponse({'code':400,'errmsg':'数据不完整'},status = 400)
        # 验证商品是否存在
        try:
            SKU.objects.get(id = sku_id)   # 如果id对应的商品不存在，则抛出异常
        except:
            return JsonResponse({'code': 400, 'errmsg': '商品不存在'},status = 400)
        # 5保存购物车数据前，先进行用户登录状态判断
        user = request.user
        # is_authenticated用户登录返回True
        if user.is_authenticated:
            # 6用户已登录，将数据保存在redis中
            # 建立redis连接
            conn = get_redis_connection('carts')
            # 将商品id和数量写入hash
            conn.hincrby('sku_count_%d' % user.id,sku_id, int(count))
            # 判断selected的状态是否为True，若为True，将商品id写入set
            if selected:
                conn.sadd('selected_%d' % user.id, sku_id)
            return JsonResponse({'code': 0, 'errmsg': 'ok'})
        else:
            response = JsonResponse({'code':0,'errmsg':'ok'})
            # 7用户未登录，将数据保存在cookie中
            # 先获取一下cookie，判断一下是否存储过cookie
            cart_cookie = request.COOKIES.get('cart_cookie')
            if cart_cookie:
                # 存储过，说明cookie数据已经进行过base64的编码处理，就需要进行解码，获取存储的cookie数据
                cart_dict = pickle.loads(base64.b64decode(cart_cookie))
            else:
                # 未存储，则赋值一个空字典进行存储数据
                cart_dict = {}
            # 判断当前的sku_id是否已经在字典中，存在，说明商品已经添加过一次，需要对数量进行累加
            if sku_id in cart_dict:
                count += int(cart_dict[sku_id]['count'])
            # 将新数据保存在字典中
            cart_dict[sku_id] = {
                'count':count,
                'selected':selected
            }
            # 对字典数据进行base64编码
            cart_cookie = base64.b64encode(pickle.dumps(cart_dict)).decode()
            # 将编码后的数据写入cookie
            response.set_cookie('cart_cookie', cart_cookie, max_age=60 * 60 * 6)

            return response

    # 获取购物车数据
    def get(self,request):
        # 1判断用户是否登录，不同登录状态用户获取不同数据
        user = request.user
        if user.is_authenticated:
            # 2登录用户，从redis中获取数据
            # 连接redis
            conn = get_redis_connection('carts')
            # 获取hash数据  {sku_id:count}
            sku_count = conn.hgetall('sku_count_%d' % user.id)
            # 获取set数据 {sku_id1,ski_id2}
            selected_sku = conn.smembers('selected_%d' % user.id)
            # 将两部分数据构造成和cookie一样的字典嵌套形式，方便在第4步共同商品数据获取的方法  sku_count获取后是一个字典,里面的数据为bytes类型需要int强制类型转换
            cart_dict = {}
            for sku_id, count in sku_count.items():
                cart_dict[int(sku_id)] = {
                    'count': int(count),
                    'selected': sku_id in selected_sku  # sku_id在集合中返回True，不在返回False
                }
        else:
            # 3未登录用户，从cookie中获取数据
            # 获取cookie数据
            cart_cookie = request.COOKIES.get('cart_cookie')
            # 判断cookie数据是否存在，在写入cookie时指定有效期，超过有效期cookie不存在
            if cart_cookie is None:
                return JsonResponse({'code': 400, 'errmsg': '数据不存在'}, status=400)
            # 存在，对cookie数据进行解码
            cart_dict = pickle.loads(base64.b64decode(cart_cookie))
        # 4根据获取到的sku_id查询sku表获取商品信息
        sku_ids = cart_dict.keys()
        skus = SKU.objects.filter(id__in=sku_ids)
        # 5构造返回的商品数据
        cart_skus = []
        for sku in skus:
            cart_skus.append({
                'id': sku.id,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'price': sku.price,
                'count': cart_dict[sku.id]['count'],
                'selected': cart_dict[sku.id]['selected']
            })
        # 6返回结果
        return JsonResponse({'code':0,'errmsg':'ok','cart_skus':cart_skus})

    # 修改购物车数据
    def put(self,request):
        # 1、获取前端传递数据，json数据
        data_json = request.body.decode()
        data_dict = json.loads(data_json)
        sku_id = data_dict.get('sku_id')
        count = data_dict.get('count')
        selected = data_dict.get('selected',True)
        # 2、验证数据
        # 2-1、验证数据的完整性
        if not all([sku_id,count]):
            return JsonResponse({'code':400,'errmsg':'参数不完整'})
        # 2-2、验证数据的准确性
        try:
            sku = SKU.objects.get(id = sku_id,is_launched=True)
        except:
            return JsonResponse({'code':400,'errmsg':'该商品不存在'})
        try:
            count = int(count)
        except:
            return JsonResponse({'code': 400, 'errmsg':'参数有误'})
            # 判断selected是否为bool值
        if selected:
            if not isinstance(selected, bool):
                return JsonResponse({'code': 400, 'errmsg':'参数selected有误'})

        # 3、判断用户是否登录
        if request.user.is_authenticated:
            # 4、若已登录，修改redis购物车数据
            # 4-1、连接redis
            conn = get_redis_connection('carts')
            # 4-2、修改购物车数据
            conn.hset('sku_count_%d' % request.user.id,sku_id, int(count))
            if selected:
                conn.sadd('selected_%d' % request.user.id, sku_id)
            else:
                conn.srem('selected_%d' % request.user.id, sku_id)
            # 将新数据保存在字典中
            cart_dict = {}
            cart_dict[sku_id] = {
                'count': count,
                'selected': selected
            }
            return JsonResponse({'code': 0, 'errmsg':'ok'})
        else:
            # 5、若未登录，修改cookie购物车数据
            cart_cookie = request.COOKIES.get('cart_cookie')
            if cart_cookie:
                # 存储过，说明cookie数据已经进行过base64的编码处理，就需要进行解码，获取存储的cookie数据
                cart_dict = pickle.loads(base64.b64decode(cart_cookie))
            else:
                # 未存储，则赋值一个空字典进行存储数据
                cart_dict = {}

            # 将新数据保存在字典中
            cart_dict[sku_id] = {
                'count': count,
                'selected': selected
            }
            # 对字典数据进行base64编码
            cart_cookie = base64.b64encode(pickle.dumps(cart_dict)).decode()
            # 7、返回结果
            response = JsonResponse({'code': 0, 'errmsg': '修改购物车成功', 'cart_dict': cart_dict})

            response.set_cookie('carts', cart_cookie, max_age=60 * 60 * 6)
            return response

    # 删除购物车
    def delete(self,request):
        # 1、获取前端数据
        data_json = request.body.decode()
        data_dict = json.loads(data_json)
        sku_id = data_dict.get('sku_id')
        # 2、验证数据
        try:
            sku = SKU.objects.get(id = sku_id,is_launched=True)
        except:
            return JsonResponse({'code':400,'errmsg':'该商品不存在'})
        # 3、判断用户是否登录
        if request.user.is_authenticated:
            # 4、若已登录，删除redis购物车数据
            # 4-1、连接redis
            conn = get_redis_connection('carts')
            # 4-2、删除购物车数据
            conn.hdel('sku_count_%d' % request.user.id, sku_id)
            conn.srem('selected_%d' % request.user.id, sku_id)
            return JsonResponse({'code': 0, 'errmsg': 'ok'})
        else:
            # 5、若未登录，修改cookie购物车数据
            response = JsonResponse({'code': 0, 'errmsg': 'ok'})
            cart_cookie = request.COOKIES.get('cart_cookie')
            if cart_cookie:
                # 存储过，说明cookie数据已经进行过base64的编码处理，就需要进行解码，获取存储的cookie数据
                cart_dict = pickle.loads(base64.b64decode(cart_cookie))
            else:
                # 未存储，则赋值一个空字典进行存储数据
                cart_dict = {}
            # 判断当前的sku_id是否已经在字典中，存在，删除数据
            if sku_id in cart_dict:
                del cart_dict[sku_id]
            # 对字典数据进行base64编码
            cart_cookie = base64.b64encode(pickle.dumps(cart_dict)).decode()
            response.set_cookie('carts', cart_cookie, max_age=60 * 60 * 6)
            return response


# 购物车全选
class CartsSelectView(View):
    def put(self,request):
        # 获取前端数据
        data_json = request.body.decode()
        data_dict = json.loads(data_json)
        selected = data_dict.get('selected')
        # 验证参数
        if selected:
            if not isinstance(selected, bool):
                return JsonResponse({'code': 0, 'errmsg': '参数selected有误'})
        # 判断用户是否登录
        if request.user.is_authenticated:
            # 若已登录，操作redis购物车
            user = request.user
            # 连接redis
            conn = get_redis_connection('carts')
            # 获取hash数据  {sku_id:count}
            sku_count = conn.hgetall('sku_count_%d' % user.id)

            # 将两部分数据构造成和cookie一样的字典嵌套形式，方便在第4步共同商品数据获取的方法  sku_count获取后是一个字典,里面的数据为bytes类型需要int强制类型转换
            cart_dict = {}
            for sku_id, count in sku_count.items():
                if selected:
                    conn.sadd('selected_%d' % request.user.id, sku_id)
                else:
                    conn.srem('selected_%d' % request.user.id, sku_id)
                cart_dict[int(sku_id)] = {
                    'selected': selected
                }
            return JsonResponse({'code': 0, 'errmsg': 'ok'})

        else:
            # 若未登录，操作cookie购物车
            response = JsonResponse({'code': 0, 'errmsg': 'ok'})
            # 获取cookie数据
            cart_cookie = request.COOKIES.get('cart_cookie')
            # 判断cookie数据是否存在，在写入cookie时指定有效期，超过有效期cookie不存在
            if cart_cookie is None:
                return JsonResponse({'code': 400, 'errmsg': '数据不存在'}, status=400)
            # 存在，对cookie数据进行解码
            cart_dict = pickle.loads(base64.b64decode(cart_cookie))
            for sku_id in cart_dict:
                cart_dict[sku_id]['selected'] = selected
            # 对字典数据进行base64编码
            cart_cookie = base64.b64encode(pickle.dumps(cart_dict)).decode()
            # 将编码后的数据写入cookie
            response.set_cookie('cart_cookie', cart_cookie, max_age=60 * 60 * 6)

            return response


# 展示商品页面简单购物车
class CartsSimpleView(View):
    def get(self,request):
        # 判断用户是否登录
        user = request.user
        if user.is_authenticated:
            # 若用户已登录，查询redis购物车
            # 连接redis
            conn = get_redis_connection('carts')
            # 获取hash数据  {sku_id:count}
            sku_count = conn.hgetall('sku_count_%d' % user.id)

            # 将数据构造成和cookie一样的字典嵌套形式，方便在第4步共同商品数据获取的方法  sku_count获取后是一个字典,里面的数据为bytes类型需要int强制类型转换
            cart_dict = {}
            for sku_id, count in sku_count.items():
                cart_dict[int(sku_id)] = {
                    'count': int(count)
                }

        else:
            # 若用户未登录，查询cookie购物车
            # 获取cookie数据
            cart_cookie = request.COOKIES.get('cart_cookie')
            # 判断cookie数据是否存在，在写入cookie时指定有效期，超过有效期cookie不存在
            if cart_cookie is None:
                return JsonResponse({'code': 400, 'errmsg': '数据不存在'}, status=400)
            # 存在，对cookie数据进行解码
            cart_dict = pickle.loads(base64.b64decode(cart_cookie))
        # 4根据获取到的sku_id查询sku表获取商品信息
        sku_ids = cart_dict.keys()
        skus = SKU.objects.filter(id__in=sku_ids)
        # 5构造返回的商品数据
        cart_skus = []
        for sku in skus:
            cart_skus.append({
                'id': sku.id,
                'name': sku.name,
                'count': cart_dict[sku.id]['count'],
                'default_image_url': sku.default_image.url
            })
        return JsonResponse({'code':0,'errmsg':'ok','cart_skus':cart_skus})
